#include "LJBoundingBox.h"
#include <cstdio>

LJBoundingBox::LJBoundingBox()
:m_ExtendR(0.f),
 m_ExtendS(0.f),
 m_ExtendT(0.f)
{}

LJVector3 LJBoundingBox::GetCenter() const
{
	return m_Center;
}

LJBoundingBox LJBoundingBox::CalculateBoundingBox(const LJVector3 *vertices, UINT num)
{
	// average position
	LJVector3 m;
	for(UINT i = 0; i < num; ++i)
	{
		m += vertices[i];
	}
	m /= num;

	// build the convariance matrix
	float c11, c22, c33, c12, c21, c13, c31, c23, c32;
	c11 = 0;
	c22 = 0;
	c33 = 0;
	c12 = c13 = c23 = 0;
	for(UINT i = 0; i < num; ++i)
	{
		float xm = vertices[i].x - m.x;
		c11 += xm * xm;

		float ym = vertices[i].y - m.y;
		c22 += ym * ym;

		float zm = vertices[i].z - m.z;
		c33 += zm * zm;

		float xmym = xm*ym;
		float xmzm = xm*zm;
		float ymzm = ym*zm;
		c12 += xmym;
		c13 += xmzm;
		c23 += ymzm;
	}
	c11 /= num;
	c22 /= num;
	c33 /= num;
	c12 /= num;
	c13 /= num;
	c23 /= num;
	c21 = c12;
	c31 = c13;
	c32 = c23;
	// column major matrix
	LJMatrix3 convarianceMat(c11, c21, c31,
			                 c12, c22, c32,
			                 c13, c23, c33);
	float eigenVals[3];
	LJMatrix3 eigenVectors = EigenSystem(convarianceMat, eigenVals);

	// insert sort
	int eigenVali[3] = {0, 1, 2};
	for(int i = 1; i < 3; ++i)
	{
		int vali = eigenVali[i];
		int j = i - 1;
		for(; j >= 0; --j)
		{
			if(ljm::absT(eigenVals[eigenVali[j]]) < ljm::absT(eigenVals[vali]))
			{
				eigenVali[j+1] = eigenVali[j];
			}
			else
			{
				break;
			}
		}
		eigenVali[j+1] = vali;
	}

	LJBoundingBox box;
	box.m_R = eigenVectors[eigenVali[0]];
	box.m_S = eigenVectors[eigenVali[1]];
	box.m_T = eigenVectors[eigenVali[2]];



	return box;
}

void FindingExtend(const LJVector3 *vertices, UINT num, const LJVector3& v, float *max, float *min)
{
	float Max = ljm::dot(vertices[0], v);
	float Min = ljm::dot(vertices[0], v);
	for(UINT i = 1; i < num; ++i)
	{
		float tmpDot = ljm::dot(vertices[i], v);
		if(tmpDot > Max)
		{
			Max = tmpDot;
		}
		else if(tmpDot < Min){
			Min = tmpDot;
		}
	}
	if(max && min)
	{
		max = Max;
		min = Min;
	}
	else
	{
		throw "There is no place for Max and Min to be returned\n";
	}
}
